#include "model.h"

void Model::parseObj(char const *path) {
    ifstream is(path, ios::in);
    if(!is.is_open()) {
        printf("Failed to open: %s\n", path);
        return;
    }
    char dirName[128] = {0};
    dir(path, dirName);
    vector<glm::vec3> positions;
    vector<glm::vec3> normals;
    vector<glm::vec2> texCoords;
    vector<Face> faces;
    while (!is.eof()) {
        char buf[1024] = {0};
        is.getline(buf, sizeof(buf));
        
        if (strncmp(buf, "v ", 2) == 0) {
            glm::vec3 position;
            sscanf(buf, "v %f %f %f", &position.x, &position.y, &position.z);
            positions.push_back(position);
        }
        if (strncmp(buf, "vn ", 3) == 0) {
            glm::vec3 normal;
            sscanf(buf, "vn %f %f %f", &normal.x, &normal.y, &normal.z);
            normals.push_back(normal);
        }
        if (strncmp(buf, "vt ", 3) == 0) {
            glm::vec2 texCoord;
            sscanf(buf, "vt %f %f", &texCoord.x, &texCoord.y);
            texCoords.push_back(texCoord);
        }
        if (strncmp(buf, "f ", 2) == 0) {
            Face face;
            sscanf(buf, "f %d/%d/%d %d/%d/%d %d/%d/%d", &face.v1[0], &face.v1[1], &face.v1[2], &face.v2[0], &face.v2[1], &face.v2[2], &face.v3[0], &face.v3[1], &face.v3[2]);
            faces.push_back(face);
        }
        if (strncmp(buf, "mtllib ", 7) == 0) {
            char mtllib[1024], tmp[128];
            sscanf(buf, "mtllib %s", tmp);
            sprintf(mtllib, "%s%s", dirName, tmp);
            ifstream is_mtllib(mtllib, ios::in);
            if(!is_mtllib.is_open()) {
                printf("Failed to open: %s\n", mtllib);
            } else {
                char map_Kd[1024] = {0};
                char map_Bump[1024] = {0};
                while (!is_mtllib.eof()) {
                    char buf[1024] = {0};
                    is_mtllib.getline(buf, sizeof(buf));
                    if (strncmp(buf, "map_Kd ", 7) == 0) {
                        sscanf(buf, "map_Kd %s", tmp);
                        sprintf(map_Kd, "%s%s", dirName, tmp);
                    }
                    if (strncmp(buf, "map_Bump ", 9) == 0) {
                        sscanf(buf, "map_Bump %s", tmp);
                        sprintf(map_Bump, "%s%s", dirName, tmp);
                    }
                }
                // printf("map_Kd: %s, map_Kd: %s\n", map_Kd, map_Bump);
                if (strlen(map_Kd) > 0) {
                    unsigned int textureid;
                    loadimg(&textureid, map_Kd);
                    Texture texture = {textureid, "texture_diffuse", ""};
                    strcpy(texture.path, map_Kd);
                    textures.push_back(texture);
                }
                if (strlen(map_Bump) > 0) {
                    unsigned int textureid;
                    loadimg(&textureid, map_Bump);
                    Texture texture = {textureid, "texture_specular", ""};
                    strcpy(texture.path, map_Bump);
                    textures.push_back(texture);
                }
            }
        }
    }
    int i_ = 0;
    for (int i = 0, l = faces.size(); i < l; ++i) {
        Vertex vertex1 = {positions[faces[i].v1[0] - 1], normals[faces[i].v1[2] - 1], texCoords[faces[i].v1[1] - 1]};
        Vertex vertex2 = {positions[faces[i].v2[0] - 1], normals[faces[i].v2[2] - 1], texCoords[faces[i].v2[1] - 1]};
        Vertex vertex3 = {positions[faces[i].v3[0] - 1], normals[faces[i].v3[2] - 1], texCoords[faces[i].v3[1] - 1]};

        vertices.push_back(vertex1);
        vertices.push_back(vertex2);
        vertices.push_back(vertex3);
        
        indices.push_back(i_++);
        indices.push_back(i_++);
        indices.push_back(i_++);
    }
    Mesh mesh(vertices, indices, textures);
    meshes.push_back(mesh);
}

void Model::draw(unsigned int shaderProgram) {
    for (int i = 0, l = meshes.size(); i < l; ++i) {
        meshes[i].draw(shaderProgram);
    }
}

void Model::setVao() {
    // 创建顶点数组
    glGenVertexArrays(1, &vao);
    // 创建顶点缓冲对象
    glGenBuffers(1, &vbo);
    // 创建顶点缓冲对象
    glGenBuffers(1, &ebo);
    // 绑定顶点数组
    glBindVertexArray(vao);
    // 绑定顶点缓冲对象
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    // 顶点数据复制到当前绑定缓冲对象
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
    // 绑定顶点缓冲对象
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    // 顶点数据复制到当前绑定缓冲对象
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(offsetof(Vertex, normal)));
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(offsetof(Vertex, texCoord)));
    // 启用顶点属性 0
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
    // 解除绑定顶点对象
    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    // 解除绑定顶点数组
    glBindVertexArray(0); 
    
}
